/*
 * @Author: Eureka 
 * @Date: 2019-09-18 15:39:15 
 * @Last Modified by: Eureka
 * @Last Modified time: 2022-04-14 10:39:41
 * Form编码方式请求类
 */

// import 'package:apptechnician/config/config.dart';
// import 'package:apptechnician/entity_factory.dart';
// import 'package:flutter_framework/flutter_framework.dart';

import 'dart:convert';

import 'package:dio/dio.dart';
import 'package:oktoast/oktoast.dart';
import 'package:rxdart/subjects.dart';
import 'package:senkoo_platform/base_enum/state_type_enum.dart';
import 'package:senkoo_platform/base_message/base_message.dart';
import 'package:senkoo_platform/base_print_log/base_print_log.dart';
import 'package:senkoo_platform/config/config.dart';

///http请求
class HttpManager {
  static const contentTypeFrom = "application/x-www-form-urlencoded";
  static late Dio _dio;
  static const int cnnecrTimeOut = 5;
  static const int reciveTimeOut = 5;
  static final Map<String, CancelToken> _cancelTokens = <String, CancelToken>{};

  HttpManager._internal() {
    initDio();
  }
  static final HttpManager _httpManger = HttpManager._internal();
  factory HttpManager() {
    return _httpManger;
  }

  //get请求
  PublishSubject<T?> get<T>(
    String url, {
    Map<String, dynamic>? queryParameters,
    bool isCancelable = true,
  }) {
    _dio.options.headers.addAll({
      "Content-Type": contentTypeFrom,
      "Authorization": AppConfig.authoriationToken,
    });
    return _requstHttp<T>(url, true, queryParameters, isCancelable);
  }

  //post请求
  PublishSubject<T?> post<T>(String url,
      {Map<String, dynamic>? queryParameters,
      bool isCancelable = true,
      bool isSHowErrorToast = true}) {
    _dio.options.headers.addAll({
      "Content-Type": contentTypeFrom,
      "Authorization": AppConfig.authoriationToken,
    });
    return _requstHttp<T>(url, false, queryParameters, isCancelable);
  }

  downLoad(url, savePath, Function downCallBack) async {
    PrintUtil.d('downLoad请求启动!');
    try {
      await _dio.download(url, savePath, onReceiveProgress: (received, total) {
        double progress = double.parse(((received / total).toStringAsFixed(4)));
        downCallBack(received, total, progress);
      });
    } on DioError catch (e) {
      if (CancelToken.isCancel(e)) {
        PrintUtil.d('downLoad请求取消! ${e.message!}');
      }
      PrintUtil.d('downLoad请求发生错误：$e');
      downCallBack(0, 0, 102.0);
    }
  }

  /// 参数说明  url 请求路径
  /// queryParamerers  是 请求参数
  /// baseWidget和baseInnerWidgetState用于 加载loading 和 设置 取消CanselToken
  /// isCancelable 是设置改请求是否 能被取消 ， 必须建立在 传入baseWidget或者baseInnerWidgetState的基础之上
  /// isShowLoading 设置是否能显示 加载loading , 同样要建立在传入 baseWidget或者 baseInnerWidgetState 基础之上
  /// isShowErrorToaet  这个是 设置请求失败后 是否要 吐司的
  // ignore: unused_element
  PublishSubject<T?> _requstHttp<T>(String url,
      [bool? isGet, queryParameters, bool? isCancelable]) {
    Future future;
    PublishSubject<T?> publishSubject = PublishSubject<T?>();
    CancelToken? cancelToken;

    if (isGet!) {
      future = _dio.get(url,
          queryParameters: queryParameters, cancelToken: cancelToken);
    } else {
      future = _dio.post(url, data: queryParameters, cancelToken: cancelToken);
    }

    future.then((data) {
      //这里要做错误处理
      //需要先过滤 error ， 根据和后台的 约定 ， 搞清楚什么是失败
      // 什么是成功
      int? dioCode = json.decode(data.toString())["code"];
      String? dioString = json.decode(data.toString())["msg"];
      dioString ??= json.decode(data.toString())["message"];
      bool isError = dioCode != 200; //不是100都是失败 其余原因需要后台告知
      if (isError) {
        PrintUtil.d(
          'isError==>$url',
        );
        // FlutterBugly.uploadException(
        //     message: 'netWorkError',
        //     detail:
        //         {'err', url, queryParameters, dioCode, dioString}.toString());
        callError(publishSubject, MyError(dioCode, dioString), url);
      } else {
        // publishSubject
        //     .add(EntityFactory.generateOBJ<T>(json.decode(data.toString())));
        publishSubject.close();
      }
    }).catchError((err) {
      PrintUtil.d(
        'catchErr==>$url',
      );
      // FlutterBugly.uploadException(
      //     message: 'catchError',
      //     detail: {'err', url, queryParameters, err.toString()}.toString());
      //后台报错
      callError(publishSubject, MyError(1, err.toString()), url);
    });
    return publishSubject;
  }

  ///请求错误以后 做的一些事情
  void callError(
    PublishSubject publishSubject,
    MyError error,
    String url,
  ) {
    publishSubject.addError(error);
    publishSubject.close();
    showToast('${error.message}');
  }

  // 422 登录失败
  // 404 not found
  // 419 token失效
  // 500 服务器内部错误
  String callErrorString(var errorCode) {
    switch (errorCode) {
      case 422:
        return BaseMessage.loginFail;
      case 409:
        return BaseMessage.loginFail;
      case 404:
        return BaseMessage.notFound;
      case 419:
        return BaseMessage.tokenInvalid;
      case 500:
        return BaseMessage.serverError;
      default:
        return BaseMessage.unknow;
    }
  }

  ///取消请求
  static void cancelHttp(String? tag) {
    if (_cancelTokens.containsKey(tag)) {
      if (!_cancelTokens[tag!]!.isCancelled) {
        _cancelTokens[tag]!.cancel();
      }
      _cancelTokens.remove(tag);
    }
  }

  ///配置dio
  void initDio() {
    _dio = Dio();
    // 配置dio实例
    _dio.options.baseUrl =
        AppConfig.setDebug ? AppConfig.debugUrl : AppConfig.productUrl;
    _dio.options.connectTimeout = const Duration(seconds: cnnecrTimeOut); //5s
    _dio.options.receiveTimeout = const Duration(seconds: reciveTimeOut); //5s ;
    // _dio.options.contentType = ContentType.parse(CONTENT_TYPE_FORM);
    _dio.options.contentType = Headers.formUrlEncodedContentType;
    _dio.options.headers.addAll({
      "Content-Type": "application/x-www-form-urlencoded",
      "Authorization": AppConfig.authoriationToken,
    });
    if (AppConfig.isDebug) {
      PrintUtil.d(AppConfig.authoriationToken);
      //此处可以增加配置项，留一个设置代理的用户给测试人员配置，然后动态读取

//      (_dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate =
//          (client) {
//        // config the http client
//        client.findProxy = (uri) {
//          //proxy all request to localhost:8888
//          return "PROXY 10.5.39.111:8888";
//        };
//        // you can also create a new HttpClient to dio
//        // return new HttpClient();
//      };
    }
  }
}

//错误代码对应的
StateType stateType(MyError err) {
  switch (err.code) {
    case 409:
      return StateType.param; //参数错误
    case 419:
      return StateType.noLogin; //koken
    case 404:
      return StateType.router; //接口路由错误
    case 500:
      return StateType.server; //服务内部错误
    default:
      return StateType.network;
  }
}

class MyError {
  int? code;
  String? message;
  MyError(this.code, this.message);
}
